home *** CD-ROM | disk | FTP | other *** search
/ Aminet 23 / Aminet 23 (1998)(GTI - Schatztruhe)[!][Feb 1998].iso / Aminet / text / edit / Smartindent.lha / Smartindent / Source / util.c < prev    next >
C/C++ Source or Header  |  1997-12-14  |  13KB  |  523 lines

  1. /*(( "Kopf" */
  2. /* -----------------------------------------------------------------------------
  3.  
  4.    $Id: util.c,v 1.4 1997/06/29 19:24:13 mshopf Exp mshopf $
  5.  
  6.    GoldED API client, ©1997 Matthias Hopf.
  7.    Compiled with SasC.
  8.  
  9.  
  10.    Utility functions.
  11.  
  12.    ------------------------------------------------------------------------------
  13. */
  14.  
  15. /*)) */
  16. /*(( "Includes" */
  17.  
  18. #include "smartindent.h"
  19. #include "util.h"
  20. #include "semantics.h"
  21.  
  22. #include <proto/exec.h>
  23.  
  24. #include <exec/types.h>
  25. #include <exec/memory.h>
  26.  
  27. #include <string.h>
  28. #include <ctype.h>
  29.  
  30. /*)) */
  31. /*(( "Daten" */
  32.  
  33. struct Semantic *Semantics[] = SEMANTICS;
  34.  
  35. int ExecVersion;
  36. int MemAllocSmallFlags;
  37.  
  38. #ifdef DEBUG
  39. int Dbug_Counter;
  40. int Dbug = 0;
  41. #endif
  42.  
  43. /* Common parser errors */
  44.  
  45. const char *SYNTAX_ERROR                = "Syntax error in line %ld";
  46. const char *UNMATCHED_BRACE_ERROR       = "Unmached brace in line %ld";
  47. const char *PRAEPROCESSOR_ERROR         = "Praeprocessor error in line %ld";
  48. const char *SUSPICIOUS_ERROR            = "Suspicious statement in line %ld";
  49. const char *STRING_TERMINATION_ERROR    = "Non-terminated string above line %ld";
  50. const char *INTERNAL_ERROR              = "!!! Internal parse error in line %ld !!!";
  51.  
  52. const char *UNKNOWN_MODE_ERROR          = "Unknown MODE. Known modes are:\n" SEMANTICS_NAMES;
  53. const char *UNSPECIFIED_MODE_ERROR      = "No MODE specified (mandatory). Known modes are:\n" SEMANTICS_NAMES;
  54.  
  55. /*)) */
  56.  
  57. /********** Private **********/
  58. /*(( "NewRequest ()" */
  59.  
  60. /* Create and initialize new APIOrder and APIModifyRequest.
  61.  * Create a (maximum sized) string, too. */
  62. static struct SmartOrder *NewRequest (sc_t *c, int Line, int Size)
  63. {
  64.     struct SmartOrder *o;
  65.  
  66.     if (! (o = AllocMem (sizeof (struct SmartOrder) + Size, MemAllocSmallFlags)) )
  67.     {
  68.     Error (c, "Out of memory in line %d");
  69.     return NULL;
  70.     }
  71.     o->Order.api_Data   = &o->Modify;
  72.     o->Modify.mr_Line   = Line;
  73.     o->Modify.mr_Data   = OrderString (o);
  74.     o->StringSize       = Size;
  75.  
  76.     return (o);
  77. }
  78.  
  79.  
  80. /*)) */
  81. /*(( "LinkRequest ()" */
  82.  
  83. /* Link outstanding Order to message. */
  84. static void LinkRequest (sc_t *c, struct SmartOrder *o)
  85. {
  86.     if (o)
  87.     {
  88.     o->Order.api_Next = c->Msg->api_Order;
  89.     c->Msg->api_Order = &o->Order;
  90.     }
  91. }
  92.  
  93.  
  94. /*)) */
  95. /*(( "DoRequest ()" */
  96.  
  97. /* Create/modify Order for the current line, but the given position.
  98.  * Old Orders are linked or expanded when necessary.
  99.  * No indentation correctness is checked, no Client values are addapted! */
  100. static void DoRequest (sc_t *c, int Pos, int Indent)
  101. {
  102.     struct SmartOrder *o = c->Req;
  103.     char *Text;
  104.     int  Len, Needed;
  105.  
  106.     /* Link old Request, when it is not one for the current line */
  107.     if (o && c->CurrentLine != o->Modify.mr_Line)
  108.     {
  109.     debug (D_REQUESTS, ("Linking for line %ld\t", o->Modify.mr_Line));
  110.     LinkRequest (c, o);
  111.     c->Req = o = NULL;
  112.     }
  113.  
  114.     GetText (c, &Text, &Len);
  115.     Needed = Indent > 0 ? Len + Indent : Len;
  116.  
  117.     /* Create new Request when necessary */
  118.     if (! o)
  119.     {
  120.     debug (D_REQUESTS, ("New Req for line %ld\t", c->CurrentLine));
  121.     if (! (c->Req = o = NewRequest (c, c->CurrentLine, Needed + ADD_SPARSE_INDENTATION)) )
  122.         return;
  123.     memcpy (OrderString (o), Text, Len);
  124.     o->Modify.mr_Size = Len;
  125.     }
  126.     /* else check size of current Request and copy it to a new one when necessary */
  127.     else if (o->StringSize < Needed)
  128.     {
  129.     debug (D_REQUESTS, ("Renew Req for line %ld old size %ld needed %ld\t", c->CurrentLine, o->StringSize, Needed));
  130.     if (! (o = NewRequest (c, c->CurrentLine, Needed + ADD_SPARSE_INDENTATION)) )
  131.         return;
  132.     memcpy (OrderString (o), Text, Len);
  133.     o->Modify.mr_Size = Len;
  134.     FreeRequest (c, c->Req);
  135.     c->Req = o;
  136.     }
  137.  
  138.     /* Now shift characters */
  139.     memmove (OrderString (o) + Pos + Indent, OrderString (o) + Pos, o->Modify.mr_Size - Pos);
  140.     if (Indent > 0)
  141.     memset  (OrderString (o) + Pos, ' ', Indent);
  142.     o->Modify.mr_Size += Indent;
  143. }
  144.  
  145.  
  146. /*)) */
  147. /*(( "DoneCursorLine ()" */
  148.  
  149. /* We have indented the current cursor line.
  150.  * Now set Cursor pos to something reasonable (when necessary). */
  151.  
  152. static void DoneCursorLine (sc_t *c)
  153. {
  154.     char *Text;
  155.     int Len, i;
  156.  
  157.     if (! (c->Mode & MODE_CURSOR))
  158.     return;
  159.  
  160.     GetText (c, &Text, &Len);
  161.  
  162.     debug (D_CURSOR, ("\nchecking line %ld, len %ld, indent %ld, cursorpos %ld\n", c->CurrentLine, Len, c->Indent, c->CursorX));
  163.  
  164.     for (i = 0; i < Len; i++)
  165.     if (! isspace (Text [i]))
  166.         break;
  167.  
  168.     debug (D_CURSOR, ("first non-space pos %ld\n", i));
  169.  
  170.     if (i < Len)
  171.     {
  172.     if (c->CursorX < i)             /* current cursorpos less than first char pos */
  173.         c->CursorX = i;
  174.  
  175.     for (i = Len-1; i >= 0; i--)
  176.         if (! isspace (Text [i]))
  177.         break;
  178.     i++;
  179.     debug (D_CURSOR, ("last non-space pos %ld, last non-space char 0x%lx\n", i-1, i> 0 ? (long) Text[i-1] : (long) '/'));
  180.     if (c->CursorX > i)             /* current cursorpos greater than last char pos */
  181.         c->CursorX = i;
  182.     }
  183.     else                                /* empty line */
  184.     c->CursorX = c->Indent;
  185. }
  186.  
  187.  
  188. /*)) */
  189.  
  190. /********** Public **********/
  191. /*(( "InitIndent ()" */
  192.  
  193. void InitIndent (sc_t *c, int BeginLine, int EndLine, int Mode)
  194. {
  195.     struct EditConfig *Edit = c->Edit;
  196.  
  197.     debug (Dbug, ("Startline %ld, EndLine %ld, Mode 0x%lx\n", BeginLine, EndLine, Mode));
  198.     memset (& (c->FirstLine), 0, sizeof (sc_t) - offsetof (sc_t, FirstLine));
  199.     c->BeginIndent = BeginLine;
  200.     c->EndIndent   = EndLine;
  201.     c->Mode        = Mode;
  202.     c->LastPos     = -1;
  203.  
  204.     c->FirstLine   = c->CurrentLine = 0; /* scan for first column "{" later */
  205.     c->Node        = Edit->TextNodes;
  206.  
  207.     c->BlockStartX = Edit->BlockStartX;
  208.     c->BlockEndX   = Edit->BlockEndX;
  209.     c->CursorX     = Edit->Column;
  210. }
  211.  
  212.  
  213. /*)) */
  214. /*(( "CleanupIndent ()" */
  215.  
  216. void CleanupIndent (sc_t *c)
  217. {
  218.     struct SmartOrder *o, **next, **last;
  219.     struct EditConfig *Edit = c->Edit;
  220.     struct LineNode *Nodes = Edit->TextNodes;
  221.  
  222.     /* Link last request */
  223.     LinkRequest (c, c->Req);
  224.     c->Req = NULL;
  225.  
  226.     /* Check requests, whether they are really necessary */
  227.     last = (struct SmartOrder **) & (c->Msg->api_Order);
  228.     o    = *last;
  229.     while (o)
  230.     {
  231.     next = (struct SmartOrder **) & (o->Order.api_Next);
  232.     debug (D_REQUESTS, ("checking request %lx for line %ld, next: %lx, last pointer: %lx\n", o, o->Modify.mr_Line, *next, last));
  233.     if (o->Modify.mr_Size == Nodes [o->Modify.mr_Line] .Len)
  234.     {
  235.         if (strncmp ((UBYTE *) (o+1), Nodes [o->Modify.mr_Line] .Text, o->Modify.mr_Size) == 0)
  236.         {
  237.         debug (D_REQUESTS, ("Freeing unnecessary request %lx for line %ld.\n", o, o->Modify.mr_Line));
  238.         *last = *next;
  239.         FreeRequest (c, o);
  240.         next  = last;
  241.         }
  242.     }
  243.     last = next;
  244.     o    = *last;
  245.     }
  246.  
  247.     /* Update display if necessary */
  248. #if 0
  249.     if (c->Msg->api_Order)
  250.     c->Msg->api_Refresh |= 0;
  251. #endif  /* Not necessary in current GoldEd version. */
  252.  
  253.     /* Create cursor move requests when necessary */
  254.     if (c->CursorX != Edit->Column)
  255.     if ( (o = NewRequest (c, Edit->Line, 0)) )
  256.     {
  257.         o->Modify.mr_Data   = NULL;
  258.         o->Modify.mr_Column = c->CursorX;
  259.         LinkRequest (c, o);
  260.         c->Msg->api_Refresh |= API_REFRESH_SYNC;
  261.     }
  262.  
  263.     /* Update block markers if necessary */
  264.     if (c->BlockStartX != Edit->BlockStartX || c->BlockEndX != Edit->BlockEndX)
  265.     {
  266.     Edit->BlockStartX = c->BlockStartX;
  267.     Edit->BlockEndX   = c->BlockEndX;
  268.     c->Msg->api_Refresh |= API_REFRESH_MARKER;
  269.     }
  270.  
  271. #ifdef DEBUG
  272.     if (Dbug & D_REQUESTS)
  273.     {
  274.     Printf ("Orders for lines ");
  275.     o = (struct SmartOrder *) c->Msg->api_Order;
  276.     while (o)
  277.     {
  278.         Printf ("%ld ", o->Modify.mr_Line);
  279.         o = (struct SmartOrder *) o->Order.api_Next;
  280.     }
  281.     Printf ("%%\n");
  282.     }
  283. #endif
  284. }
  285.  
  286.  
  287. /*)) */
  288. /*(( "FreeRequest ()" */
  289.  
  290. /* Free the APIOrder, APIModifyRequest and the string space. */
  291. void FreeRequest (sc_t *c, struct SmartOrder *Req)
  292. {
  293.     debug (D_REQUESTS, ("Freeing request for line %ld\t", Req->Modify.mr_Line));
  294.     FreeMem (Req, sizeof (struct SmartOrder) + Req->StringSize);
  295. }
  296.  
  297.  
  298. /*)) */
  299. /*(( "GetText ()" */
  300.  
  301. /* Get *real* current text and length */
  302.  
  303. void GetText (sc_t *c, char **Text, int *Len)
  304. {
  305.     if (c->Req && c->Req->Modify.mr_Line == c->CurrentLine)
  306.     {
  307.     *Text = OrderString (c->Req);
  308.     *Len  = c->Req->Modify.mr_Size;
  309.     }
  310.     else if (c->Edit->Line == c->CurrentLine && c->Edit->CurrentBuffer)
  311.     {
  312.     *Text = c->Edit->CurrentBuffer;
  313.     *Len  = c->Edit->CurrentLen;
  314.     }
  315.     else
  316.     {
  317.     *Text = c->Node->Text;
  318.     *Len  = c->Node->Len;
  319.     }
  320. }
  321.  
  322.  
  323. /*)) */
  324. /*(( "Move ()" */
  325.  
  326. /* Move current line contents at position Pos when indentation is enabled
  327.  * for the current line.
  328.  * Perform indentation correctness checks. */
  329. void Move (sc_t *c, int Pos, int NewPos)
  330. {
  331.     char *text;
  332.     int  len, i, line;
  333.  
  334.     if (Pos == NewPos)
  335.     return;
  336.  
  337.     debug (D_MOVE, ("Move(%ld->%ld)[Cur %ld]\t", Pos, NewPos, c->CurrentPos));
  338.  
  339.     line = c->CurrentLine;
  340.     /* don't do anything when we are out of limits */
  341.     if (line < c->BeginIndent || line > c->EndIndent)
  342.     return;
  343.  
  344.     if (NewPos < 0)
  345.     NewPos = 0;
  346.  
  347.     GetText (c, &text, &len);
  348.  
  349.     if (len < 1)
  350.     {
  351.     Error (c, "Move () on empty line %d!");
  352.     return;
  353.     }
  354.  
  355.     /* When there's nothing to shift, exit */
  356.     if (Pos >= len)
  357.     return;
  358.  
  359.     /* Backindent only as far as we are only killing spaces */
  360.     if (NewPos < Pos)
  361.     {
  362.         /* We want at least one space before the new position */
  363.     for (i = Pos+1; i > NewPos; i--)
  364.         if (i >= 2 && text [i-2] != ' ')
  365.         break;
  366.         /* We cannot shift without breaking the rules */
  367.     if (i >= Pos)
  368.         return;
  369.     NewPos = i;
  370.     }
  371.  
  372.     i = NewPos - Pos;
  373.     DoRequest (c, Pos, i);
  374.  
  375.     if (c->CurrentPos >= Pos)
  376.     c->CurrentPos += i;
  377.     if (c->NextPos >= Pos)
  378.     c->NextPos += i;
  379.     if (c->NextPosEOL >= Pos)
  380.     c->NextPosEOL += i;
  381.  
  382.     if (line == c->Edit->Line        && c->CursorX     >= Pos)
  383.     c->CursorX     += i;
  384.     if (line == c->Edit->BlockStartY && c->BlockStartX >= Pos)
  385.     c->BlockStartX += i;
  386.     if (line == c->Edit->BlockEndY   && c->BlockEndX   >= Pos)
  387.     c->BlockEndX   += i;
  388.  
  389.     debug (D_MOVE, ("Res(%ld)[Cur %ld]\t", i, c->CurrentPos));
  390. }
  391.  
  392.  
  393. /*)) */
  394. /*(( "NextWord ()" */
  395.  
  396. /* Get the next word (maximum length MAX_WORD_LEN-1).
  397.  * Returns an empty word after EOF.
  398.  * Sets Current* when Flag is set. */
  399. void NextWord (sc_t *c, char *buf, int Flag)
  400. {
  401.     char  *text;
  402.     int    len, i, res;
  403.     int    line        = c->CurrentLine;
  404.     int    pos         = c->NextPos;
  405.     int    last        = c->CurrentPos;
  406.     struct LineNode *n = c->Node;
  407.     char  *copy        = buf;
  408.     int  (*IsWord) (struct SmartClient *c, char *buf, int len, int maxlen) = c->Sem->IsWord;
  409.  
  410.     *buf = '\0';
  411.  
  412.     /* We may continue to scan the current line */
  413.     GetText (c, &text, &len);
  414.     /* Has an unget happened? */
  415.     if (last == pos)
  416.     last = -1;
  417.  
  418.     for (;;)
  419.     {
  420.         /* First make sure we have something to scan. */
  421.     if (pos < 0 || pos >= len || IS_FOLD (n))
  422.     {
  423.         if (line == c->Edit->Line && Flag)
  424.         {
  425.         c->CurrentLine = line;
  426.         c->Node        = n;
  427.         DoneCursorLine (c);
  428.         }
  429.         if (++line >= c->Edit->Lines)
  430.         {
  431.         c->CurrentLine = c->EndIndent +1; /* we are finished */
  432.         return;
  433.         }
  434.         n++;
  435.  
  436.         /* not nice - this should be able to use GetText()... */
  437.         if (c->Edit->Line == line && c->Edit->CurrentBuffer)
  438.         {
  439.         text = c->Edit->CurrentBuffer;
  440.         len  = c->Edit->CurrentLen;
  441.         }
  442.         else
  443.         {
  444.         text = n->Text;
  445.         len  = n->Len;
  446.         }
  447.  
  448.         pos  = 0;
  449.         last = -1;
  450.         continue;
  451.     }
  452.  
  453.         /* Then skip whitespace */
  454.     if (! isspace (text[pos]))
  455.         break;
  456.     pos++;
  457.     }
  458.  
  459.     /* Now copy chars as long as they belong to the word and they fit into the buffer */
  460.     res = MATCH_FALSE;
  461.     for (i = pos; i < len && copy < buf + MAX_WORD_LEN-1; )
  462.     {
  463.     if ( (res = (*IsWord) (c, &text [pos], i-pos+1, len-pos)) == MATCH_FALSE )
  464.         break;
  465.     *copy++ = text [i++];
  466.     *copy   = '\0';
  467.     if (res == MATCH_EXACT)
  468.         break;
  469.     }
  470.  
  471.     /* Adapt Environment when Flag is set */
  472.     if (! Flag)
  473.     {
  474.     debug (D_WORD, ("%ld<%s>\t", pos, buf));
  475.     return;
  476.     }
  477.  
  478.     /* Now skip remaining chars as long as they belong to the word */
  479.     if (res == MATCH_TRUE)
  480.     while (i < len && (res = (*IsWord) (c, &text [pos], i-pos+1, len-pos)) != MATCH_FALSE)
  481.     {
  482.         i++;
  483.         if (res == MATCH_EXACT)
  484.         break;
  485.     }
  486.  
  487.     /* Now skip whitespace */
  488.     while (i < len && isspace (text [i]))
  489.     i++;
  490.     if (i >= len)
  491.     i = -1;
  492.  
  493.     debug (D_WORD, ("%ld%s%s[%s]\t", pos, last < 0 ? "b" : "", i < 0 ? "e" : "", buf));
  494.  
  495.     c->CurrentLine = line;
  496.     c->CurrentPos  = pos;
  497.     c->Node        = n;
  498.     c->NextPos     = c->NextPosEOL = i;
  499.     c->LastPos     = last;
  500. }
  501.  
  502.  
  503. /*)) */
  504. /*(( "LastWord ()" */
  505.  
  506. void LastWord (sc_t *c)
  507. {
  508.     int i;
  509.     c->NextPos = c->NextPosEOL = c->CurrentPos;
  510.     c->LastPos = -1;
  511.     for (i = c->CurrentPos-1; i >= 0; i--)
  512.     if (! isspace (c->WordBuffer [i]))
  513.     {
  514.         c->CurrentPos = i;
  515.         return;
  516.     }
  517.     c->CurrentPos = -1;
  518. }
  519.  
  520.  
  521. /*)) */
  522.  
  523.